﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace QSearcher.QCrawler
{
    public class Crawler
    {
        private bool isRunning = false;
        public bool IsRunning { get { return isRunning; } }

        private List<Thread> thPoolRequest = new List<Thread>();
        private List<Thread> thPoolAnalyze = new List<Thread>();
        private List<Thread> thPoolDownload = new List<Thread>();

        private Requester requester = new Requester();
        private Downloader downloader = new Downloader();

        public event Action Stoped;

        public void Start(uint thSizeRequest, uint thSizeAnalyze, Action<int>[] workAnalyze, uint thSizeDownload)
        {
            if (thSizeRequest <= 0 && thSizeAnalyze <= 0 && thSizeDownload <= 0)
            {
                if (Stoped != null) Stoped();
                return;
            }
            isRunning = true;
            thPoolRequest = new List<Thread>();
            Start(thSizeRequest, requester.Run, ref thPoolRequest);
            thPoolDownload = new List<Thread>();
            Start(thSizeDownload, downloader.Run, ref thPoolDownload);
            thPoolAnalyze = new List<Thread>();
            if (workAnalyze != null)
            {
                foreach (var work in workAnalyze)
                    Start(thSizeAnalyze, work, ref thPoolAnalyze);
            }
        }
        private void Start(uint thSize, Action<int> work, ref List<Thread> thPool)
        {
            if (work != null)
            {
                for (int i = 0; i < thSize; i++)
                {
                    var th = new Thread(new ThreadStart(() =>
                    {
                        while (isRunning)
                        {
                            work(i);
                            GC.Collect();
                        }
                        var thActiveCount = thPoolRequest.Count(p => { return p.ThreadState == ThreadState.Running; })
                            + thPoolAnalyze.Count(p => { return p.ThreadState == ThreadState.Running; })
                            + thPoolDownload.Count(p => { return p.ThreadState == ThreadState.Running; });
                        if (thActiveCount <= 0) if (Stoped != null) Stoped();
                    })) { IsBackground = true };
                    thPool.Add(th);
                    th.Start();
                }
            }
        }

        public void Stop()
        {
            isRunning = false;
        }

        public static void CheckDirectory(string file)
        {
            var fileInfo = new FileInfo(file);
            var path = fileInfo.Directory;
            Stack<DirectoryInfo> dirs = new Stack<DirectoryInfo>();
            while (path != null)
            {
                dirs.Push(path);
                path = path.Parent;
            }
            while (dirs.Count > 0)
            {
                var dir = dirs.Pop();
                if (!dir.Exists) dir.Create();
            }
        }
        public static string UrlToPath(string url)
        {
            string[] notFileChar = { @"\", ":", "*", "?", ">", "<", "|" };
            foreach (var ch in notFileChar) url = url.Replace(ch, "-");
            if (url[url.Length - 1] == '/') url += Path.DirectorySeparatorChar + "index.htm";
            url = url.Replace("/", Path.DirectorySeparatorChar + "");
            return url;
        }
    }
}
